<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Object.assign()方法</title>
</head>
<body>
  <script>
    // assign 本意为分配
    // 基本用法 Object.assign()方法用于对象的合并，将源对象(source)的所有可枚举属性，复制到目标对象(target)
    var target = {a: 1};
    var source1 = {b: 2, c: 2};
    var source2 = {c: 3};
    Object.assign(target,source1,source2);
    console.log(target)// {a: 1, b: 2, c: 3}
    // 如果只有一个参数，Object.assign()会直接返回该参数
    var obj = {a: 1};
    Object.assign(obj) === obj; // true
    // 如果该参数不是对象，则会先转成对象，然后返回。
    typeof Object.assign(2); // object
    //由于undefined和null无法转成对象，所以如果它们作为参数，就会报错。
    Object.assign(null); // 报错
    Object.assign(undefined);
    /**
     * 如果非对象参数出现在源对象的位置(即非首参数)，那么处理规则有所不同。
     * 首先，这些参数都会转成对象，如果无法转成对象，就会跳过。
     * 这意味着，如果undefined和null不在首参数，就不会报错。
    */
  </script>
  <script>
    var obj = {a: 1};
    Object.assign(obj, undefined) === obj; // true
    Object.assign(obj, null) === obj; //true
    /**
     * 其他类型的值(即数值，字符串和布尔值)不在首参数，也不会报错。
     * 但是，除了字符串会以数组形式拷贝入目标对象，其他的值都不会产生效果。
    */
   var v1 ='abc';
   var v2 = true;
   var v3 = 10;
   var obj = Object.assign({}, v1, v2, v3);
   console.log(obj); // {0: "a", 1: "b", 2: "c"}
  </script>
  <script>
    // 1. 浅拷贝
    /**
     * Object.assign()方法实行的是浅拷贝，而不是深拷贝。也就是说，如果源对象某个属性的值是对象。
     * 那么目标对象拷贝得到的是这个对象的引用。
    */
   var obj1 = {a: {b: 1}};
   var obj2 = Object.assign({}, obj1);
   obj1.a.b = 2;
   console.log(obj2);//{a: {b: 2}}
   // 2.同名属性的替换
   //对于这种嵌套的对象，一旦遇到同名属性，Object.assign()的处理方法是替换，而不是添加。
   var target = {a: {b: 'c', d: 'e'}};
   var source = {a: {b: 'hello'}}
   var a = Object.assign(target, source);
   console.log(a)// // { a: { b: 'hello' } }
   /**
    * 上面代码中，target对象的a属性被source对象的a属性整个替换掉了。而不会得到{ a: { b: 'hello', d: 'e' } }的结果。
    * 这通常不是开发者想要的，需要特别小心。一些函数库提供Object.assign()的定制版本
    * 比如lodash的_.defaultsDeep()方法，可以得到深拷贝的合并。
   */
  // 3.数组的处理
  // Object.assign()可以用来处理数组，但是会把数组视为对象。
   var b = Object.assign([1,2,3],[4,5]);
   console.log(b);//[4, 5, 3]
   /**
    * 上面代码中，数组被视为对象处理 [1,2,3]转为对象是 {0: 1, 1: 2, 2: 3}
    * [4,5]转为对象是                                {0: 4, 1: 5},
    * 所以最终结果是 [4,5,3]
   */
  // 4.取值函数的处理
  // Object.assign()只能进行值的复制，如果要复制的值是一个取值函数，那么将求值后再复制
  var source = {
    get foo() { return 1}
  };
  var target = {};
  var c = Object.assign(target, source);
  console.log(c) // {foo: 1}
  </script>
  <script>
    // 常见用途： Object.assign()方法有很多用处
    // 1.为对象添加属性。
    class Point{
      constructor(x,y) {
        Object.assign(this,{x,y})
      }
    }
    // 上面方法通过Object.assign()方法将x属性和y属性添加到Point类的对象实例。
    //2.为对象添加方法。
    Object.assign(SomeClass.prototype, {
      someMethod(arg1, arg2) {
        //code
      },
      anotherMethod() {
        //code
      }
    });
    // 等同于下面的写法
    SomeClass.prototype.someMethod = function(arg1, arg2) {
      // code
    };
    SomeClass.prototype.anotherMethod = function () {
      // code
    }
    // 上面代码使用了对象属性的简洁表示法，直接将俩个函数放在大括号中，再使用assign方法添加到SomeClass.prototype之中。
    // 3.克隆对象 不做多解释
    // 4.合并多个对象
    // 5.为属性指定默认值
  </script>
</body>
</html>